////////////////////////////////////////////////
// DESCRIPTION:
//     HandleMap Structure for device drivers
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//

#pragma once

#include <handle_map.hxx>

namespace FusionWare
{
    namespace DFX
    {
        ///////////////////////////////////////////////////////
        // Description: 
        //    Template class to wrap up the management of mapping handles 
        //    to the context instances used by the driver.
        //
        // Remarks:
        //    The ContextSmartPtr template parameter *MUST* be a smart pointer
        //    with ref counting so that the underlying object is deleted when
        //    no longer needed.
        //
        //    HandleType must be able to cast to/from void*
        //
        //    All methods are thread safe using an internal locking. This is
        //    acceptable now that Macallan supports synch calls in the power
        //    down thread.
        //
        //
        template<class ContextTypeSmartPtr, class HandleType=DWORD>
        class HandleMap : protected ce::handle_map<ContextTypeSmartPtr>
        {
        public:
            HandleMap() {}

            ///////////////////////////////////////////////////////
            // Description: 
            //    Get the context associated with the handle in the map
            //
            // Input: 
            //    Handle  - "Handle" for a context created by the Add() method
            //    bool  
            // Returns: 
            //    ContextTypeSmartPtr or NULL
            //     
            // Remarks: 
            //    This method retrieves a Context smart pointer that is associated
            //    with the specified handle in a previous call to Add(). 
            //
            ContextTypeSmartPtr GetValidContext(HandleType Handle)
            {
                AUTO_CS(this->maplock);

                ContextTypeSmartPtr pContext = find((void*)Handle);
                if (!pContext)
                    SetLastError(ERROR_INVALID_HANDLE);

                return pContext;
            }

            ///////////////////////////////////////////////////////
            // Description: 
            //    Add a new context to the map
            //
            // Input: 
            //    pContext - New context to add to the map
            //
            // Returns: 
            //    DWORD - "Handle" for the new context to provide to the OS
            //     
            // Remarks: 
            //    Adds the context into the map. The returned "handle" can be returned 
            //    to the device manager as the context handle.
            //
            // Note: 
            //    The returned "handle" is not a true Win32 OS Handle. It is just 
            //    a DWORD value that can later be used with GetValidContext to get
            //    back a context.
            //
            HandleType Add(ContextTypeSmartPtr pContext)
            {
                AUTO_CS(this->maplock);        
                return (HandleType)insert(pContext);
            }

            ///////////////////////////////////////////////////////
            // Description: 
            //    Remove a context from the map based on it's "handle"
            // 
            // Input: 
            //    Handle - "handle" value created by a previous call to Add
            //
            // Returns: 
            //    BOOL 
            //     
            // Remarks: 
            //    Removes a context from the map based on it's handle. Due to the
            //    use of smart_ptr the underlying object is destroyed when this
            //    method exits.
            //
            bool Remove(HandleType Handle)
            {
                AUTO_CS(this->maplock);
        
                // unfortunately erase does not indicate status 
                // so for verification find the handle in the map first.
                ContextTypeSmartPtr pContext = find((void*)Handle);
                if(!pContext)
                {
                    SetLastError(ERROR_INVALID_HANDLE);
                    return false;
                }

                erase((void*)Handle);
                return true;
            }

        protected:
            FusionWare::Threads::CriticalSection maplock;
        };
    }
}